"""
Copyright (c) 2022 Huawei Technologies Co.,Ltd.

openGauss is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:

          http://license.coscl.org.cn/MulanPSL2

THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
"""
"""
Case Type   : 硬件故障类--磁盘
Case Name   : 使用gsql工具导入过程中，磁盘空间不足
Create At   : 2020-10-20
Owner       : n@ningyali
Description :使用gsql工具导入过程中，磁盘空间不足
    1、 数据库里面建表写入大量数据，使用gs_dump导出（导出数据大小800M）
    gs_dump -W ****** -f backup/zz_t1.sql -p 2900 test -F p
    2、使用DFR-Runner工具给磁盘写入大量数据，使得剩余空间小于上一步导出的文件大小
    3、新建database，使用gsql命令导入第1步导出来的数据库文件
    gsql -d dbname -p 2900 -U user -f ./zz_t1.sql
    4、清理故障后，重新执行gsql导入
Expect      :
    1、gs_dump导出成功
    2、磁盘空间不足故障注入成功
    3、gsql导入失败，并提示空间不足
    4、故障消除成功
    5、gsql导入成功
History     :
    modified:2021-3-3 by 5328113;注入主机磁盘满故障后、执行完导出来的数据库文件后，增加主备状态查询步骤；
        并增加断言条件，有可能注入故障后主机已经stop；
"""

import unittest

from yat.test import Node
from yat.test import macro

from testcase.utils.Common import *
from testcase.utils.CommonSH import *


class GsDumpAndDiskFull(unittest.TestCase):
    primary_sh = CommonSH('PrimaryDbUser')
    standby1_sh = CommonSH('Standby1DbUser')
    nodes_tuple = ('PrimaryDbUser', 'Standby1DbUser', 'Standby2DbUser')

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.log = Logger()
        self.log.info('----Opengauss_Reliability_Hardware_Case015:开始执行----')
        self.primary_root_node = Node(node='PrimaryRoot')
        self.primary_user_node = Node(node='PrimaryDbUser')
        self.standby1_root_node = Node(node='Standby1Root')
        self.standby1_user_node = Node(node='Standby1DbUser')
        self.standby2_root_node = Node(node='Standby2Root')
        self.standby2_user_node = Node(node='Standby2DbUser')
        self.com = Common()
        self.Constant = Constant()
        self.new_db_name = 'reliability_hardware015'
        dump_file_name = 'reliability_hardware015.sql'
        self.back_up_path = os.path.join(macro.DB_BACKUP_PATH, dump_file_name)

        self.log.info("----获取主节点数据目录所在磁盘 ----")
        cmd = f"df -h {macro.DB_INSTANCE_PATH}"
        self.log.info(cmd)
        msg = self.primary_root_node.sh(cmd).result()
        self.log.info(msg)
        self.db_disk_name = msg.splitlines()[-1].split()[0].strip()

    def test_main(self):
        self.log.info("----数据库里面建表写入大量数据，使用gs_dump导出(导出数据大于400M)----")
        # tpcc建仓和执行已产生大量数据，直接使用gs_dump导出
        dump_result = self.primary_sh.dumpFile(self.back_up_path, cmd='-F p',
                                               get_detail=False)
        self.log.info(dump_result)
        self.assertTrue(dump_result)

        shell_cmd = f"ls -lh {self.back_up_path}"
        self.log.info(shell_cmd)
        msg = self.primary_root_node.sh(shell_cmd).result()
        self.log.info(msg)

        self.log.info("----获取主机磁盘剩余空间值----")
        avail_size = self.com.getAvailSize(self.primary_root_node,
                                           macro.DB_INSTANCE_PATH)
        self.log.info('Available:' + avail_size)

        self.log.info("----新建database----")
        sql_cmd = f"drop database if exists {self.new_db_name}; " \
            f"create database {self.new_db_name}"
        self.log.info(sql_cmd)
        msg = self.primary_sh.executDbSql(sql_cmd)
        self.log.info(msg)
        self.assertIn(self.Constant.CREATE_DATABASE_SUCCESS_MSG, msg)

        self.log.info("----注入磁盘满故障----")
        cfe_command = f'rfile_full (diskname) values ({self.db_disk_name})'
        cfe_msg = self.com.cfe_inject(self.primary_root_node, cfe_command)
        self.log.info(cfe_msg)
        self.assertIn(self.Constant.CFE_DISK_FULL_SUCCESS_MSG, cfe_msg)

        self.primary_sh.getDbClusterStatus('status')

        self.log.info("----使用gsql命令导入第1步导出来的数据库文件----")
        gsql_cmd = f'source {macro.DB_ENV_PATH}; ' \
            f'gsql -d {self.new_db_name} ' \
            f'-p {self.primary_user_node.db_port} ' \
            f'-f {self.back_up_path}'
        self.log.info(gsql_cmd)
        msg = self.primary_user_node.sh(gsql_cmd).result()
        self.log.info(msg)
        self.primary_sh.getDbClusterStatus('status')
        self.assertTrue(self.Constant.DISK_FULL_MSG in msg or
                        self.Constant.FAILED_CONNECT_DB in msg)

        self.log.info("----清理磁盘留出足够的空间----")
        cfe_command = f"rfile_full where (diskname={self.db_disk_name})"
        cfe_msg = self.com.cfe_clean(self.primary_root_node, cfe_command)
        self.log.info(cfe_msg)
        self.assertIn(self.Constant.CFE_DISK_CLEAN_SUCCESS_MSG, cfe_msg)

        self.log.info("----磁盘满可能导致数据库主节点stop，重启集群以恢复----")
        self.primary_sh.stopDbCluster()
        is_started = self.primary_sh.startDbCluster()
        self.log.info(is_started)

        self.assertTrue(self.primary_sh.getDbClusterStatus('status'))

        self.log.info("----新建database----")
        sql_cmd = f"drop database if exists {self.new_db_name}; " \
            f"create database {self.new_db_name}"
        self.log.info(sql_cmd)
        msg = self.primary_sh.executDbSql(sql_cmd)
        self.log.info(msg)
        self.assertIn(self.Constant.CREATE_DATABASE_SUCCESS_MSG, msg)

        self.log.info("----清理故障后，重新执行gsql导入----")
        self.log.info(gsql_cmd)
        msg = self.primary_user_node.sh(gsql_cmd).result()
        self.log.info(msg)
        for error_msg in self.Constant.SQL_WRONG_MSG:
            self.assertNotIn(error_msg, msg)

    def tearDown(self):
        cfe_command = f"rfile_full where (diskname={self.db_disk_name})"
        cfe_msg = self.com.cfe_clean(self.primary_root_node, cfe_command)
        self.log.info(cfe_msg)
        self.assertIn(self.Constant.CFE_DISK_CLEAN_SUCCESS_MSG, cfe_msg)

        self.log.info("----删除新建库----")
        sql_cmd = f"drop database {self.new_db_name}"
        self.log.info(sql_cmd)
        msg = self.primary_sh.executDbSql(sql_cmd)
        self.log.info(msg)

        self.log.info("----删除备份文件----")
        shell_cmd = f"rm -rf {self.back_up_path}; ls -l {self.back_up_path}"
        self.log.info(shell_cmd)
        msg = self.primary_root_node.sh(shell_cmd).result()
        self.log.info(msg)

        self.log.info('----Opengauss_Reliability_Hardware_Case015:执行完成----')
